package com.xqboss.apps.service.guild;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.domain.guild.GuildApplyRecord;
import com.xqboss.apps.enums.guild.GuildApplyConsumeStatusEnum;
import com.xqboss.apps.enums.guild.GuildApplyOrInviteStatusEnum;
import com.xqboss.apps.mapper.guild.GuildApplyRecordMapper;
import com.xqboss.apps.vo.guild.GuildJoinApplyRecordVo;
import com.xqboss.apps.vo.guild.GuildMyApplyRecordVo;
import com.xqboss.common.exception.ServiceException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 公会申请记录表——会员操作(GuildApplyRecord)表服务实现类
 *
 *
 * @author LJH
 * @since 2024-01-09 17:21:10
 */
@Service
public class GuildApplyRecordService extends ServiceImpl<GuildApplyRecordMapper, GuildApplyRecord> {

    /**
     * 获取当前用户的公会申请记录
     *
     * @param userId 用户id
     * @return 我的申请
     */
    public IPage<GuildMyApplyRecordVo> getMyApplyRecordVo(Page<GuildMyApplyRecordVo> page,Long userId) {
        Assert.notNull(userId,()->new ServiceException("用户id不能为空！"));
        return this.getBaseMapper().getMyApplyRecordVo(page,userId);
    }

    /**
     * 记录用户公会申请
     *
     * 重复申请生成一条数据，并刷新最新申请时间
     *
     * @param guildId 公会id
     * @param userId 用户id
     * @param consumeStatus 消耗状态
     */
    @Transactional(rollbackFor = Exception.class)
    public void recordApply(Long guildId, Long userId, GuildApplyConsumeStatusEnum consumeStatus) {
        Assert.notNull(guildId,()->new ServiceException("公会id不能为空！"));
        Assert.notNull(userId,()->new ServiceException("用户id不能为空！"));
        GuildApplyRecord applyRecord = this.lambdaQuery()
                .eq(GuildApplyRecord::getApplyGuildId, guildId)
                .eq(GuildApplyRecord::getApplyUserId, userId)
                .eq(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.APPROVED)
                .one();
        if (ObjUtil.isNotEmpty(applyRecord)) {
            applyRecord.setUpdateTime(LocalDateTime.now());
            applyRecord.setConsumeStatus(consumeStatus);
            boolean update = this.updateById(applyRecord);
            Assert.isTrue(update,()->new ServiceException("重复申请更新申请记录失败~"));
            return;
        }
        applyRecord = GuildApplyRecord.builder().applyGuildId(guildId).applyUserId(userId).applyStatus(GuildApplyOrInviteStatusEnum.APPROVED).consumeStatus(consumeStatus).build();
        boolean save = this.save(applyRecord);
        Assert.isTrue(save,()->new ServiceException("添加用户公会申请记录失败~"));
    }

    /**
     * 获取某公会的会员申请记录
     *
     * @param guildId 公会id
     */
    public IPage<GuildJoinApplyRecordVo> getJoinApplyList(Page<GuildJoinApplyRecordVo> page, Long guildId) {
        Assert.notNull(guildId,()->new ServiceException("公会id不能为空！"));
        return this.getBaseMapper().getJoinApplyList(page,guildId);
    }

    /**
     * 修改申请状态-会长操作
     *
     * @param guildId 申请的公会id
     * @param userId 申请的用户id
     * @param status 要更新的申请状态
     */
    @Transactional(rollbackFor = Exception.class)
    public GuildApplyRecord updateApplyStatus(Long guildId, Long userId, GuildApplyOrInviteStatusEnum status) {
        Assert.notNull(guildId,()->new ServiceException("公会id不能为空！"));
        Assert.notNull(userId,()->new ServiceException("用户id不能为空！"));
        Assert.notNull(status,()->new ServiceException("申请状态不能为空！"));
        GuildApplyRecord record = this.lambdaQuery()
                .eq(GuildApplyRecord::getApplyGuildId, guildId)
                .eq(GuildApplyRecord::getApplyUserId, userId)
                .eq(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.APPROVED)
                .one();
        Assert.notNull(record,()->new ServiceException("申请记录不存在~"));
        boolean update = this.lambdaUpdate()
                .set(GuildApplyRecord::getApplyStatus, status)
                .eq(GuildApplyRecord::getApplyGuildId, guildId)
                .eq(GuildApplyRecord::getApplyUserId, userId)
                .eq(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.APPROVED)
                .update();
        Assert.isTrue(update,()->new ServiceException("申请状态更新失败~"));
        return record;
    }

    /**
     * 已申请到公会的用户。该用户其它公会申请状态为 待审核 的修改为 已超时
     *
     * @param userId 会长审核通过的用户id
     */
    @Transactional(rollbackFor = Exception.class)
    public void actionApplyTimeoutUser(Long userId) {
        Assert.notNull(userId,()->new ServiceException("用户id不能为空！"));
        // 先判断有无要修改的
        Long count = this.lambdaQuery()
                .eq(GuildApplyRecord::getApplyUserId, userId)
                .eq(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.APPROVED)
                .count();
        if(count==0)return;
        // 批量修改申请状态为已超时
        boolean update = this.lambdaUpdate()
                .set(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.TIMED_OUT)
                .eq(GuildApplyRecord::getApplyUserId, userId)
                .eq(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.APPROVED)
                .update();
        Assert.isTrue(update,()->new ServiceException("申请状态更新为已超时失败~"));
    }

    /**
     * 公会已满员 或 公会解散，那么所有申请过该公会的申请状态 修改为：已超时
     *
     * @param guildId 申请过该公会的公会id
     */
    @Transactional(rollbackFor = Exception.class)
    public void actionApplyTimeoutGuild(Long guildId) {
        Assert.notNull(guildId,()->new ServiceException("公会id不能为空！"));
        // 先判断有无要修改的
        Long count = this.lambdaQuery()
                .eq(GuildApplyRecord::getApplyGuildId, guildId)
                .eq(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.APPROVED)
                .count();
        if(count==0)return;
        // 批量修改申请状态为已超时
        boolean update = this.lambdaUpdate()
                .set(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.TIMED_OUT)
                .eq(GuildApplyRecord::getApplyGuildId, guildId)
                .eq(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.APPROVED)
                .update();
        Assert.isTrue(update,()->new ServiceException("申请状态更新为已超时失败~"));
    }

    /**
     * 查看该用户 【只要没加入公会且消耗了材料的申请】。满足这情况，用户在还没有加入到公会前，可以随意的申请公会和加入邀请的公会，都不将消耗材料
     *
     * @param userId 用户id
     * @return true-表示有 消耗了材料的申请，但申请为：待通过 或 已拒绝 或 已超时
     */
    public boolean isApplyUnJoined(Long userId) {
        Assert.notNull(userId,()->new ServiceException("用户id不能为空！"));
        Long count = this.lambdaQuery()
                .eq(GuildApplyRecord::getApplyUserId, userId)
                .eq(GuildApplyRecord::getConsumeStatus, GuildApplyConsumeStatusEnum.CONSUME_OK)
                .ne(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.JOINED)
                .count();
        return count!=0;
    }

    /**
     * 作废已消耗
     *
     * ======加入公会通过之后，把【是否有被拒绝的申请】或【还未审核通过的申请】或【已超时的申请】这三种情况 的已消耗材料状况作废=======
     *
     * @param userId 用户id
     * @param isApplyUnJoined 【是否有被拒绝的申请】或【还未审核通过的申请】或【已超时的申请】 ，并且消耗了材料
     */
    public void cancelConsume(boolean isApplyUnJoined,Long userId) {
        if (!isApplyUnJoined) {
            return;
        }
        Assert.notNull(userId,()->new ServiceException("用户id不能为空！"));
        if (!isApplyUnJoined(userId)) {
            return;
        }
        boolean update = this.lambdaUpdate()
                .set(GuildApplyRecord::getConsumeStatus, GuildApplyConsumeStatusEnum.CONSUME_DEL)
                .eq(GuildApplyRecord::getApplyUserId, userId)
                .eq(GuildApplyRecord::getConsumeStatus, GuildApplyConsumeStatusEnum.CONSUME_OK)
                .ne(GuildApplyRecord::getApplyStatus, GuildApplyOrInviteStatusEnum.JOINED)
                .update();
        Assert.isTrue(update,()->new ServiceException("作废已消耗失败~"));
    }
}

